package com.tuling.code.algorithm.loadbalance.complex;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

/**
 * 权重轮询调度算法(WeightedRound-RobinScheduling)-Java实现
 * @author javaw
 */
public class WeightedRoundRobinScheduling {
	//上一次选择的服务器
	private int currentIndex = -1;
	
	//当前调度的权值
	private int currentWeight = 0;
	
	//最大权重
	private int maxWeight = 0;
	
	//所有服务器权重的最大公约数
	private int gcdWeight = 0;
	
	//服务器数量
	private int serverCount = 0;
	
	//服务器列表
	private List<Server> serverList;
	
	/**
	 * 返回a , b的最大公约数
	 * @return
	 */
	private int gcd(int a , int b){
		BigInteger n1 = new BigInteger(String.valueOf(a));
		BigInteger n2 = new BigInteger(String.valueOf(b));
		BigInteger gcd = n1.gcd(n2);
		return gcd.intValue();
	}
	
	/**
	 * 获取所有服务器权重的最大公约数
	 * @return
	 */
	private int getGcdForServers(List<Server> srvList ){
		int w = 0;
		for(int i =0 , len = srvList.size();i < len-1 ; i++){
			if(w == 0){
				w = gcd(srvList.get(i).getWeight()
						, srvList.get(i + 1).getWeight());
			} else {
				w = gcd(w, srvList.get(i+1).getWeight());
			}
		}
		return w;
	}
	
	/**
	 * 获取所有服务器列表中最大的权重值
	 * @param srvList
	 * @return
	 */
	private int getMaxWeightForServers(List<Server> srvList){
		int w = 0;
		for(int i = 0, len = serverList.size(); i < len - 1; i++){
			if(w == 0){
				w = Math.max(srvList.get(i).getWeight(), srvList.get(i+1).getWeight());
			} else {
				w = Math.max(w, srvList.get(i+1).getWeight());
			}
		}
		return w;
	}
	
	
	/**
	 * 初始化服务列表以及参数
	 */
	public void init(){
		 Server s1 = new Server("192.168.0.100", 10);//3
		 Server s2 = new Server("192.168.0.101", 8);//2
		 Server s3 = new Server("192.168.0.102", 6);//6
		 Server s4 = new Server("192.168.0.103", 4);//4
		 Server s5 = new Server("192.168.0.104", 2);//1
		 serverList = new ArrayList<Server>();
		 serverList.add(s1);
		 serverList.add(s2);
		 serverList.add(s3);
		 serverList.add(s4);
		 serverList.add(s5);  
		 currentIndex = -1;
		 currentWeight = 0;
		 serverCount = serverList.size();
		 maxWeight = getMaxWeightForServers(serverList);
		 gcdWeight = getGcdForServers(serverList);
		 
		 System.out.println("maxWeight="+maxWeight + " , gcdWeight="+gcdWeight);
	}
	
	/**
	 * 	算法流程
	 * 	假设有一组服务器 S = {S0, S1, …, Sn-1}
	 *  有相应的权重，变量currentIndex表示上次选择的服务器
	 *  权值currentWeight初始化为0，currentIndex初始化为-1 ，
	 *  当第一次获取的时候返回 -->权值取最大的那个服务器
	 *  通过权重的不断递减 寻找 适合的服务器返回，直到轮询结束，权值返回为0 
	 * @return
	 */
	public Server getServer(){
		while(true){
			currentIndex = (currentIndex + 1) % serverCount;
			if(currentIndex == 0){
				currentWeight = currentWeight - gcdWeight;
				if(currentWeight <= 0){
					currentWeight = maxWeight;  //第一次获取的时候，返回权值最大的那个服务器
					if(currentWeight == 0){
						return null; //未找到最优服务器
					}
				}
			}
			
			if(serverList.get(currentIndex).getWeight() >= currentWeight){
				return serverList.get(currentIndex);
			}
		}
	}
}
